package com.cardone.common.util;

import com.cardone.common.io.FsManager;
import com.cardone.context.ContextHolder;
import com.cardone.context.action.Run1Action;
import com.cardone.context.action.Run3Action;
import com.cardone.context.function.Execution2Function;
import com.cardone.context.function.Execution4Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * excel工具类
 *
 * @author yaohaitao
 */
@Slf4j
public class ExcelUtils {
    private ExcelUtils() {
    }

    /**
     * 读取文件名
     *
     * @param filename        文件名
     * @param excelConfigList excel配置集合
     * @param paramMap
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readFilename(final String filename, final List<ExcelConfig> excelConfigList, Map<String, Object> paramMap) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        ExcelUtils.readFile(new File(filename), excelConfigList, paramMap);
    }

    /**
     * 读取文件
     *
     * @param file            文件
     * @param excelConfigList excel配置集合
     * @param paramMap
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readFile(final File file, final List<ExcelConfig> excelConfigList, Map<String, Object> paramMap) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        final Workbook workbook = create(file);

        ExcelUtils.readWorkbookForExcelConfigs(workbook, excelConfigList, paramMap);
    }

    public static Workbook create(File file) throws IOException, InvalidFormatException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.toString());
        }

        try {
            OPCPackage pkg = OPCPackage.open(file);
            return new XSSFWorkbook(pkg);
        } catch (Exception e) {
            NPOIFSFileSystem fs = new NPOIFSFileSystem(file);
            return new HSSFWorkbook(fs.getRoot(), true);
        }
    }

    /**
     * 读取工作薄
     *
     * @param workbook        工作薄
     * @param excelConfigList excel配置集合
     * @param paramMap
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readWorkbookForExcelConfigs(final Workbook workbook, final List<ExcelConfig> excelConfigList, Map<String, Object> paramMap) throws InstantiationException, IllegalAccessException {
        for (final ExcelConfig excelConfig : excelConfigList) {
            ExcelUtils.readWorkbookForExcelConfig(workbook, excelConfig, paramMap);
        }
    }

    /**
     * 读取工作薄
     *
     * @param workbook    工作薄
     * @param excelConfig excel配置
     * @param paramMap
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readWorkbookForExcelConfig(final Workbook workbook, final ExcelConfig excelConfig, Map<String, Object> paramMap) throws InstantiationException, IllegalAccessException {
        if (ArrayUtils.isNotEmpty(excelConfig.getSheetIndexs())) {
            for (final int sheetIndex : excelConfig.getSheetIndexs()) {
                final Sheet sheet = workbook.getSheetAt(sheetIndex);

                if (excelConfig.getAction() != null) {
                    excelConfig.getAction().run(sheet);
                }

                ExcelUtils.readSheet(sheet, excelConfig, paramMap);
            }

            return;
        }

        if (ArrayUtils.isEmpty(excelConfig.getSheetNames())) {
            return;
        }

        for (final String sheetName : excelConfig.getSheetNames()) {
            final Sheet sheet = workbook.getSheet(sheetName);

            if (excelConfig.getAction() != null) {
                excelConfig.getAction().run(sheet);
            }

            ExcelUtils.readSheet(sheet, excelConfig, paramMap);
        }
    }

    /**
     * 读取Sheet
     *
     * @param sheet       Sheet
     * @param excelConfig excel配置
     * @param paramMap
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readSheet(final Sheet sheet, final ExcelConfig excelConfig, Map<String, Object> paramMap) throws InstantiationException, IllegalAccessException {
        int rowIndex = 0;

        do {
            final int rownum = (rowIndex++) + excelConfig.getFirstRowIndex();

            final Row row = sheet.getRow(rownum);

            if (row == null) {
                return;
            }

            Map<String, Object> rowData;

            if (excelConfig.getReadRowFunction() == null) {
                rowData = ExcelUtils.readRow(row, excelConfig.getColumns());
            } else {
                rowData = excelConfig.getReadRowFunction().execution(row, rownum, excelConfig.getColumns(), paramMap);
            }

            if (rowData == null) {
                continue;
            }

            if (excelConfig.getDataList() == null) {
                excelConfig.setDataList(Lists.<Map<String, Object>>newArrayList());
            }

            excelConfig.getDataList().add(rowData);

            if (excelConfig.getValidateData() == null) {
                continue;
            }

            if (BooleanUtils.isTrue(excelConfig.getValidateData().execution(rowData, paramMap))) {
                if (excelConfig.getSucceedDataList() == null) {
                    excelConfig.setSucceedDataList(Lists.<Map<String, Object>>newArrayList());
                }

                excelConfig.getSucceedDataList().add(rowData);

                continue;
            }

            if (excelConfig.getErrorDataList() == null) {
                excelConfig.setErrorDataList(Lists.<Map<String, Object>>newArrayList());
            }

            excelConfig.getErrorDataList().add(rowData);
        } while (true);
    }

    /**
     * 读取行
     *
     * @param row     行
     * @param columns 列定义
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static Map<String, Object> readRow(final Row row, final Map<Integer, String> columns) throws InstantiationException, IllegalAccessException {
        final Map<String, Object> map = Maps.newHashMap();

        int notEmptyCells = 0;

        for (final Entry<Integer, String> columnEntry : columns.entrySet()) {
            final Cell cell = row.getCell(columnEntry.getKey());

            if (cell == null) {
                map.put(columnEntry.getValue(), null);

                continue;
            }

            final int type = cell.getCellType();

            if (type == Cell.CELL_TYPE_BOOLEAN) {
                boolean booleanCellValue = cell.getBooleanCellValue();

                map.put(columnEntry.getValue(), booleanCellValue);
            } else if (type == Cell.CELL_TYPE_NUMERIC) {
                double numericCellValue = cell.getNumericCellValue();

                map.put(columnEntry.getValue(), numericCellValue);
            } else {
                String stringCellValue = cell.getStringCellValue();

                map.put(columnEntry.getValue(), stringCellValue);

                if (org.apache.commons.lang3.StringUtils.isNotBlank(stringCellValue)) {
                    notEmptyCells++;
                }
            }
        }

        if (notEmptyCells < 1) {
            return null;
        }

        return map;
    }

    /**
     * 读取文件流
     *
     * @param is              InputStream
     * @param excelConfigList excel配置集合
     * @param paramMap
     * @return
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void readInputStream(final InputStream is, final List<ExcelConfig> excelConfigList, Map<String, Object> paramMap) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        final Workbook workbook = WorkbookFactory.create(is);

        ExcelUtils.readWorkbookForExcelConfigs(workbook, excelConfigList, paramMap);
    }

    /**
     * 写入文件名
     *
     * @param excelConfigList excel配置集合
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeFilename(final String templateFileName, String outFileName, final List<ExcelConfig> excelConfigList) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        ExcelUtils.writeFile(new File(templateFileName), outFileName, excelConfigList);
    }

    /**
     * 写入文件
     *
     * @param excelConfigList excel配置集合
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeFile(final File templateFile, String outFileName, final List<ExcelConfig> excelConfigList) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        final Workbook templateWorkbook = create(templateFile);

        String outFileNameExtension = FilenameUtils.getExtension(outFileName);

        Workbook workbook;

        if ("xls".equalsIgnoreCase(outFileNameExtension)) {
            workbook = new HSSFWorkbook();
        } else {
            workbook = new SXSSFWorkbook(1000);
        }

        for (final ExcelConfig excelConfig : excelConfigList) {
            for (final int sheetIndex : excelConfig.getSheetIndexs()) {
                final Sheet templateheet = templateWorkbook.getSheetAt(sheetIndex);

                if (templateheet == null) {
                    continue;
                }

                final Sheet sheet = workbook.createSheet(templateheet.getSheetName());

                try {
                    ExcelUtils.copySheet(sheet, templateheet, workbook, templateWorkbook, excelConfig.getFirstRowIndex());
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }

                ExcelUtils.writeSheet(sheet, excelConfig);
            }
        }

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            workbook.write(outputStream);

            byte[] outBuff = outputStream.toByteArray();

            try (InputStream inputStream = new ByteArrayInputStream(outBuff)) {
                ContextHolder.getBean(FsManager.class).saveFile(inputStream, outBuff.length, outFileName, "application/x-excel");
            }
        } catch (IOException e1) {
            log.error(e1.getMessage(), e1);
        }
    }

    /**
     * 写入工作薄
     *
     * @param workbook        工作薄
     * @param excelConfigList excel配置集合
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeWorkbookForExcelConfigs(final Workbook workbook, final List<ExcelConfig> excelConfigList) throws InstantiationException, IllegalAccessException {
        for (final ExcelConfig excelConfig : excelConfigList) {
            ExcelUtils.writeWorkbookForExcelConfig(workbook, excelConfig);
        }
    }

    /**
     * 写入工作薄
     *
     * @param workbook    工作薄
     * @param excelConfig excel配置
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeWorkbookForExcelConfig(final Workbook workbook, final ExcelConfig excelConfig) throws InstantiationException, IllegalAccessException {
        if (ArrayUtils.isNotEmpty(excelConfig.getSheetIndexs())) {
            for (final int sheetIndex : excelConfig.getSheetIndexs()) {
                final Sheet sheet = workbook.getSheetAt(sheetIndex);

                if (excelConfig.getAction() != null) {
                    excelConfig.getAction().run(sheet);
                }

                ExcelUtils.writeSheet(sheet, excelConfig);
            }

            return;
        }

        if (ArrayUtils.isEmpty(excelConfig.getSheetNames())) {
            return;
        }

        for (final String sheetName : excelConfig.getSheetNames()) {
            final Sheet sheet = workbook.getSheet(sheetName);

            if (excelConfig.getAction() != null) {
                excelConfig.getAction().run(sheet);
            }

            ExcelUtils.writeSheet(sheet, excelConfig);
        }
    }

    /**
     * 写入Sheet
     *
     * @param sheet       Sheet
     * @param excelConfig excel配置
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeSheet(final Sheet sheet, final ExcelConfig excelConfig) throws InstantiationException, IllegalAccessException {
        if (CollectionUtils.isEmpty(excelConfig.getDataList())) {
            return;
        }

        int rowIndex = 0;

        List<Map<String, Object>> dataList;

        if (WriteDataType.ALL.equals(excelConfig.writeDataType)) {
            dataList = excelConfig.getDataList();
        } else if (WriteDataType.SUCCEED.equals(excelConfig.writeDataType)) {
            dataList = excelConfig.getSucceedDataList();
        } else {
            dataList = excelConfig.getErrorDataList();
        }

        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }

        for (final Map<String, Object> rowData : dataList) {
            final int rownum = (rowIndex++) + excelConfig.getFirstRowIndex();

            final Row row = sheet.createRow(rownum);

            for (final Entry<Integer, String> columnEntry : excelConfig.getColumns().entrySet()) {
                final Object value = rowData.get(columnEntry.getValue());

                if (value == null) {
                    continue;
                }

                final Cell cell = row.createCell(columnEntry.getKey());

                if (value instanceof Double) {
                    cell.setCellValue((Double) value);
                } else if (value instanceof BigDecimal) {
                    cell.setCellValue(value.toString());
                } else if (value instanceof Date) {
                    cell.setCellValue((Date) value);
                } else if (value instanceof Integer) {
                    cell.setCellValue((Integer) value);
                } else if (value instanceof Boolean) {
                    cell.setCellValue((Boolean) value);
                } else if (value instanceof Calendar) {
                    cell.setCellValue((Calendar) value);
                } else {
                    cell.setCellValue(String.valueOf(value));
                }
            }
        }
    }

    /**
     * 写入流
     *
     * @param response
     * @param downFilename     下载文件名
     * @param templateFileName 模板文件名称
     * @param excelConfigList  excel配置集合
     * @throws Exception
     */
    public static void writeHttpServletResponse(final HttpServletResponse response, final String downFilename, final String templateFileName, final List<ExcelConfig> excelConfigList) throws Exception {
        response.setContentType("application/x-msdownload");
        response.setHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(downFilename, "UTF-8"));

        final Workbook templateWorkbook = create(new File(templateFileName));

        final Workbook workbook = new SXSSFWorkbook(1000);

        for (final ExcelConfig excelConfig : excelConfigList) {
            for (final int sheetIndex : excelConfig.getSheetIndexs()) {
                final Sheet templateheet = templateWorkbook.getSheetAt(sheetIndex);

                if (templateheet == null) {
                    continue;
                }

                final Sheet sheet = workbook.createSheet(templateheet.getSheetName());

                ExcelUtils.copySheet(sheet, templateheet, workbook, templateWorkbook, excelConfig.getFirstRowIndex());

                ExcelUtils.writeSheet(sheet, excelConfig);
            }
        }

        try (java.io.OutputStream out = response.getOutputStream()) {
            workbook.write(out);

            out.flush();

            response.flushBuffer();
        }
    }

    /**
     * 功能：拷贝sheet
     * 实际调用     copySheet(targetSheet, sourceSheet, targetWork, sourceWork, true)
     *
     * @param targetSheet
     * @param sourceSheet
     * @param targetWork
     * @param sourceWork
     * @param endRowIndex
     */
    public static void copySheet(Sheet targetSheet, Sheet sourceSheet, Workbook targetWork, Workbook sourceWork, int endRowIndex) throws Exception {
        copySheet(targetSheet, sourceSheet, targetWork, sourceWork, endRowIndex, true);
    }

    /**
     * 功能：拷贝sheet
     *
     * @param targetSheet
     * @param sourceSheet
     * @param targetWork
     * @param sourceWork
     * @param endRowIndex
     * @param copyStyle   boolean 是否拷贝样式
     */
    public static void copySheet(Sheet targetSheet, Sheet sourceSheet, Workbook targetWork, Workbook sourceWork, int endRowIndex, boolean copyStyle) throws Exception {
        if (targetSheet == null || sourceSheet == null || targetWork == null || sourceWork == null) {
            throw new IllegalArgumentException("调用copySheet()方法时，targetSheet、sourceSheet、targetWork、sourceWork都不能为空，故抛出该异常！");
        }

        if (endRowIndex < 1) {
            return;
        }

        //复制源表中的行
        int maxColumnNum = 0;

        Map<String, CellStyle> styleMap = null;

        if (copyStyle) {
            styleMap = Maps.newHashMap();
        }

        for (int i = sourceSheet.getFirstRowNum(); i < endRowIndex; i++) {
            Row sourceRow = sourceSheet.getRow(i);

            if (sourceRow == null) {
                continue;
            }

            Row targetRow = targetSheet.createRow(i);

            copyRow(targetRow, sourceRow, targetWork, sourceWork, styleMap);

            if (sourceRow.getLastCellNum() > maxColumnNum) {
                maxColumnNum = sourceRow.getLastCellNum();
            }
        }

        //复制源表中的合并单元格
        mergerRegion(targetSheet, sourceSheet);

        //设置目标sheet的列宽
        for (int i = 0; i <= maxColumnNum; i++) {
            targetSheet.setColumnWidth(i, sourceSheet.getColumnWidth(i));
        }
    }

    /**
     * 功能：拷贝row
     * @param targetRow
     * @param sourceRow
     * @param targetWork
     * @param sourceWork
     * @param styleMap
     */
    public static void copyRow(Row targetRow, Row sourceRow, Workbook targetWork, Workbook sourceWork, Map<String, CellStyle> styleMap) throws Exception {
        if (targetRow == null || sourceRow == null || targetWork == null || sourceWork == null ) {
            throw new IllegalArgumentException("调用copyRow()方法时，targetRow、sourceRow、targetWork、sourceWork都不能为空，故抛出该异常！");
        }

        //设置行高
        targetRow.setHeight(sourceRow.getHeight());

        for (int i = sourceRow.getFirstCellNum(); i <= sourceRow.getLastCellNum(); i++) {
            Cell sourceCell = sourceRow.getCell(i);

            if (sourceCell == null) {
                continue;
            }

            Cell targetCell = targetRow.getCell(i);

            if (targetCell == null) {
                targetCell = targetRow.createCell(i);
            }

            //拷贝单元格，包括内容和样式
            copyCell(targetCell, sourceCell, targetWork, sourceWork, styleMap);
        }
    }

    /**
     * 功能：拷贝cell，依据styleMap是否为空判断是否拷贝单元格样式
     *
     * @param targetCell 不能为空
     * @param sourceCell 不能为空
     * @param targetWork 不能为空
     * @param sourceWork 不能为空
     * @param styleMap   可以为空
     */
    public static void copyCell(Cell targetCell, Cell sourceCell, Workbook targetWork, Workbook sourceWork, Map<String, CellStyle> styleMap) {
        if (targetCell == null || sourceCell == null || targetWork == null || sourceWork == null) {
            throw new IllegalArgumentException("调用copyCell()方法时，targetCell、sourceCell、targetWork、sourceWork都不能为空，故抛出该异常！");
        }

        CellStyle sourceCellStyle = sourceCell.getCellStyle();

        //处理单元格样式
        if ((styleMap != null) && (sourceCellStyle != null)) {
            if (targetWork == sourceWork) {
                targetCell.setCellStyle(sourceCellStyle);
            } else {
                Object cellStyleHashCode = sourceCellStyle.hashCode();

                if (cellStyleHashCode != null) {
                    String cellStyle = cellStyleHashCode.toString();

                    CellStyle targetCellStyle = styleMap.get(cellStyle);

                    if (targetCellStyle == null) {
                        targetCellStyle = targetWork.createCellStyle();
                        targetCellStyle.cloneStyleFrom(sourceCellStyle);
                        styleMap.put(cellStyle, targetCellStyle);
                    }

                    targetCell.setCellStyle(targetCellStyle);
                }
            }
        }

        //处理单元格内容
        switch (sourceCell.getCellType()) {
            case Cell.CELL_TYPE_STRING:
                targetCell.setCellValue(sourceCell.getRichStringCellValue());
                break;
            case Cell.CELL_TYPE_NUMERIC:
                targetCell.setCellValue(sourceCell.getNumericCellValue());
                break;
            case Cell.CELL_TYPE_BLANK:
                targetCell.setCellType(Cell.CELL_TYPE_BLANK);
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                targetCell.setCellValue(sourceCell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_ERROR:
                targetCell.setCellErrorValue(sourceCell.getErrorCellValue());
                break;
            case Cell.CELL_TYPE_FORMULA:
                targetCell.setCellFormula(sourceCell.getCellFormula());
                break;
            default:
                break;
        }
    }

    /**
     * 功能：复制原有sheet的合并单元格到新创建的sheet
     *
     * @param targetSheet
     * @param sourceSheet
     */
    public static void mergerRegion(Sheet targetSheet, Sheet sourceSheet) throws Exception {
        if (targetSheet == null || sourceSheet == null) {
            throw new IllegalArgumentException("调用mergerRegion()方法时，targetSheet或者sourceSheet不能为空，故抛出该异常！");
        }

        for (int i = 0; i < sourceSheet.getNumMergedRegions(); i++) {
            CellRangeAddress oldRange = sourceSheet.getMergedRegion(i);

            CellRangeAddress newRange = new CellRangeAddress(oldRange.getFirstRow(), oldRange.getLastRow(), oldRange.getFirstColumn(), oldRange.getLastColumn());

            targetSheet.addMergedRegion(newRange);
        }
    }

    /**
     * 写入文件流
     *
     * @param is              InputStream
     * @param excelConfigList excel配置集合
     * @return
     * @throws InvalidFormatException
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void writeInputStream(final InputStream is, final List<ExcelConfig> excelConfigList) throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
        final Workbook workbook = WorkbookFactory.create(is);

        ExcelUtils.writeWorkbookForExcelConfigs(workbook, excelConfigList);
    }

    /**
     * 写入行
     *
     * @param row     行
     * @param columns 列定义
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static Map<String, Object> writeRow(final Row row, final Map<Integer, String> columns) throws InstantiationException, IllegalAccessException {
        final Map<String, Object> map = Maps.newHashMap();

        for (final Entry<Integer, String> columnEntry : columns.entrySet()) {
            final Cell cell = row.getCell(columnEntry.getKey());

            if (cell == null) {
                map.put(columnEntry.getValue(), null);

                continue;
            }

            final int type = cell.getCellType();

            if (type == Cell.CELL_TYPE_BOOLEAN) {
                map.put(columnEntry.getValue(), cell.getBooleanCellValue());
            } else if (type == Cell.CELL_TYPE_NUMERIC) {
                map.put(columnEntry.getValue(), cell.getNumericCellValue());
            } else {
                map.put(columnEntry.getValue(), cell.getStringCellValue());
            }
        }

        return map;
    }

    public static enum WriteDataType {
        ALL,
        SUCCEED,
        ERROR
    }

    /**
     * excel配置
     *
     * @author yaohaitao
     */
    @Getter
    @Setter
    public static class ExcelConfig {
        /**
         * sheet索引集合
         */
        int[] sheetIndexs = {};
        /**
         * sheet名称集合
         */
        String[] sheetNames;

        private WriteDataType writeDataType = WriteDataType.ERROR;
        /**
         * 动作
         */
        private Run1Action<Sheet> action;
        /**
         * 列定义
         */
        private Map<Integer, String> columns;
        /**
         * 数据集合
         */
        private List<Map<String, Object>> dataList;
        /**
         * 错误数据集合
         */
        private List<Map<String, Object>> errorDataList;
        /**
         * 开始行索引
         */
        private int firstRowIndex;
        /**
         * 读取行方法
         */
        private Execution4Function<Map<String, Object>, Row, Integer, Map<Integer, String>, Map<String, Object>> readRowFunction;
        /**
         * 成功数据集合
         */
        private List<Map<String, Object>> succeedDataList;
        /**
         * 验证方法
         */
        private Execution2Function<Boolean, Map<String, Object>, Map<String, Object>> validateData;
        /**
         * 写入动作
         */
        private Run3Action<Map<String, Object>, Row, Integer> writeRowAction;

        /**
         * 禁止实例化
         */
        private ExcelConfig() {
        }

        /**
         * 实例化
         *
         * @param columns 列定义
         * @return excel配置
         */
        public static ExcelConfig newExcelConfig(final Map<Integer, String> columns) {
            final ExcelConfig excelConfig = new ExcelConfig();

            excelConfig.setColumns(columns);

            return excelConfig;
        }
    }
}
